package psd.model.Prolog.Converters;

import java.util.Iterator;

import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;

import psd.model.IConverter;
import psd.model.Prolog.FactGenerationToolbox;
import psd.model.Prolog.PrologConverter;

public class PrologTypeDeclarationConverter extends PrologConverter implements
		IConverter<TypeDeclaration> {

	public PrologTypeDeclarationConverter(FactGenerationToolbox toolbox) {
		super(toolbox);
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean convert(TypeDeclaration node) {
		String defaultConstructorId = handleDefaultConstructors(node);
        visitAbstractTypeDeclaration(node, defaultConstructorId, null);
        handleRelationships(node);
        return true;
	}
	
    private void handleRelationships(TypeDeclaration node)
    {
        String id = generationToolBox.getIDResolver().getID(node);
        if(node.isInterface())
        {
        	generationToolBox.getFactWriter().writeFact("interfaceT", new String[] {
                id, this.getFilePath(node), this.getLineNumber(node)
            });

        }
        Type superClassTyper = node.getSuperclassType();
        String superClass;
        if(superClassTyper != null)
        {
            superClass = generationToolBox.getIDResolver().getID(superClassTyper.resolveBinding());
        } else
        {
            //superClass = generationToolBox.getIDResolver().getJavaLangObjectID();
        	superClass = "'object'";
        }
        
        generationToolBox.getFactWriter().writeFact("extendsT", new String[] {
            id, superClass, this.getFilePath(node), this.getLineNumber(node)
        });
        for(Iterator implementsIterator = node.superInterfaceTypes().iterator(); implementsIterator.hasNext(); )
        {
            Type type = (Type)implementsIterator.next();
            String arg[] = {
                id, generationToolBox.getIDResolver().getID(type.resolveBinding()), this.getFilePath(node), this.getLineNumber(node)
            };
            generationToolBox.getFactWriter().writeFact("implementsT", arg);
        }

        if(!node.isLocalTypeDeclaration())
        {
            generationToolBox.getSyntheticConstructorIds().clear();
        }
    }

	
	private String handleDefaultConstructors(TypeDeclaration node)
    {
        boolean foundConstructor = false;
        Iterator i = node.bodyDeclarations().iterator();
        while(i.hasNext()) 
        {
            BodyDeclaration bdd = (BodyDeclaration)i.next();
            if(bdd.getNodeType() != 31)
            {
                continue;
            }
            MethodDeclaration md = (MethodDeclaration)bdd;
            if(!md.isConstructor())
            {
                continue;
            }
            foundConstructor = true;
            break;
        }
        if(!foundConstructor && !node.isInterface())
        {
            String synthConstrId = createSynteticConstructor(node);
            return synthConstrId;
        } else
        {
            return null;
        }
    }
	
	private String createSynteticConstructor(TypeDeclaration typeDeclaration)
    {
        ITypeBinding binding = typeDeclaration.resolveBinding();
        String fqn = generationToolBox.getIDResolver().getSyntheticConstructorID(binding);
        String bodyID = generationToolBox.getIDResolver().getID();
        if(typeDeclaration.isLocalTypeDeclaration())
        {
            fqn = generationToolBox.getIDResolver().getID();
            generationToolBox.getSyntheticConstructorIds().put(binding, fqn);
        } else
        {
            fqn = generationToolBox.getFQNTranslator().transformFQN(fqn);
        }
        String args[] = {
            fqn, generationToolBox.getIDResolver().getID(typeDeclaration), "'<init>'", "[]", "type(basic, void, 0)", "[]", bodyID, this.getFilePath(typeDeclaration), this.getLineNumber(typeDeclaration) 
        };
        
        generationToolBox.getFactWriter().writeFact("methodDefT", args);
        args = (new String[] {
            fqn, "public", this.getFilePath(typeDeclaration), this.getLineNumber(typeDeclaration)
        });
        generationToolBox.getFactWriter().writeFact("modifierT", args);
        args[1] = "synthetic";
        generationToolBox.getFactWriter().writeFact("modifierT", args);
        
        String execID = generationToolBox.getIDResolver().getID();
        String applyID = generationToolBox.getIDResolver().getID();
        args = (new String[] {
            bodyID, fqn, fqn, (new StringBuilder("[")).append(execID).append("]").toString(), this.getFilePath(typeDeclaration), this.getLineNumber(typeDeclaration)
        });
        generationToolBox.getFactWriter().writeFact("blockT", args);
        args = (new String[] {
            execID, bodyID, fqn, applyID, this.getFilePath(typeDeclaration), this.getLineNumber(typeDeclaration)
        });
        Type type = typeDeclaration.getSuperclassType();
        String superc;
        if(type != null)
        {
            superc = generationToolBox.getIDResolver().getSyntheticConstructorID(type.resolveBinding());
        } else
        {
            superc = generationToolBox.getIDResolver().getSyntheticConstructorID(null);
        }
        generationToolBox.getFQNTranslator().transformFQN(superc);
        generationToolBox.getFactWriter().writeFact("execT", args);
        args = (new String[] {
            applyID, execID, fqn, "'null'", "'super'", PrologCommon.getEmptyList(), superc, this.getFilePath(typeDeclaration), this.getLineNumber(typeDeclaration)
        });
        generationToolBox.getFactWriter().writeFact("callT", args);
        return fqn;
    }	
	
	
	
}
